/*
 * CleanWTF - Cleans stale saved variables from a World of Warcraft WTF folder
 *
 * Originally written by Elunaria of US-Gorgonnash, you may freely distribute, modify, bundle or
 * incorporate this source code how you wish. There is no public license associated with it and
 * it was written for personal use. Enjoy.
 */

#include <windows.h>
#include <iostream>
#include <list>
#include <string>
#include <algorithm>

using namespace std;
list<string> getFileList(string dirPath);
list<string> getDirList(string dirPath);

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cerr << "usage: cleanwtf <WoW-directory>" << endl;
        return -1;
    }

    int cleanedFileCount = 0;
    string addOnPath = string(argv[1]) + "\\Interface\\AddOns";
    string wtfPath = string(argv[1]) + "\\WTF\\Account";

    cout << "CleanWTF v1.0 by Elunaria of US-Gorgonnash" << endl
         << "------------------------------------------" << endl
         << "beginning clean of " << wtfPath << endl;

    list<string> addOnList = getDirList(addOnPath);
    list<string> accountList = getDirList(wtfPath);

    for (list<string>::iterator acctItr = accountList.begin(); acctItr != accountList.end(); acctItr++)
    {
        string accountPath = wtfPath + "\\" + *acctItr;
        list<string> realmList = getDirList(accountPath);

        for (list<string>::iterator realmItr = realmList.begin(); realmItr != realmList.end(); realmItr++)
        {
            string realmPath = accountPath + "\\" + *realmItr;
            list<string> charList = getDirList(realmPath);

            for (list<string>::iterator charItr = charList.begin(); charItr != charList.end(); charItr++)
            {
                string charPath = realmPath + "\\" + *charItr + "\\SavedVariables";
                list<string> varList = getFileList(charPath);

                if (!varList.empty())
                {
                    cout << "cleaning saved variables for account: "
                         << ", character: " << "" << endl;
                           acctItr->c_str(), charItr->c_str(), realmItr->c_str());

                    for (list<string>::iterator varItr = varList.begin(); varItr != varList.end(); varItr++)
                    {
                        size_t suffix = varItr->find(".lua");
                        if  (suffix != string::npos)
                        {
                            string fileName = charPath + "\\" + *varItr;
                            string addOn = varItr->substr(0, suffix);
                            if (find(addOnList.begin(), addOnList.end(), addOn) == addOnList.end())
                            {
                                printf("%s not installed - deleting %s\n", addOn.c_str(), fileName.c_str());
                                DeleteFile(fileName.c_str());
                                cleanedFileCount++;
                            }
                        }
                    }
                }
            }
        }

        string varPath = accountPath + "\\SavedVariables";
        list<string> varList = getFileList(varPath);

        if (!varList.empty())
        {
            printf("cleaning global saved variables for account: %s...\n", acctItr->c_str());

            for (list<string>::iterator varItr = varList.begin(); varItr != varList.end(); varItr++)
            {
                size_t suffix = varItr->find(".lua");
                if  (suffix != string::npos)
                {
                    string fileName = varPath + "\\" + *varItr;
                    string addOn = varItr->substr(0, suffix);
                    if (find(addOnList.begin(), addOnList.end(), addOn) == addOnList.end())
                    {
                        printf("%s not installed - deleting %s\n", addOn.c_str(), fileName.c_str());
                        DeleteFile(fileName.c_str());
                        cleanedFileCount++;
                    }
                }
            }
        }

    }

    if (cleanedFileCount > 0)
        printf("clean of %s complete, %d files were deleted.\n", wtfPath.c_str(), cleanedFileCount);
    else
        printf("no stale files were found, nothing to be done.\n");

    return 0;
}

list<string> getDirList(string dirPath)
{
    WIN32_FIND_DATA ffd;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    list<string> dirList;
    string realmDir = dirPath + "\\*";

    hFind = FindFirstFile(realmDir.c_str(), &ffd);
    if (INVALID_HANDLE_VALUE != hFind)
    {
        do
        {
            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                string dirName = string(ffd.cFileName);
                if (dirName != "." && dirName != ".." && dirName != "SavedVariables")
                    dirList.push_back(dirName);
            }
        }
        while (FindNextFile(hFind, &ffd) != 0);
    }
    if (GetLastError() != ERROR_NO_MORE_FILES)
        dirList.clear();
    FindClose(hFind);
    return dirList;
}

list<string> getFileList(string dirPath)
{
    WIN32_FIND_DATA ffd;
    HANDLE hFind = INVALID_HANDLE_VALUE;
    list<string> fileList;
    string fileDir = dirPath + "\\*";
    hFind = FindFirstFile(fileDir.c_str(), &ffd);
    if (INVALID_HANDLE_VALUE != hFind)
    {
        do
        {
            if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
            {
                string fileName = string(ffd.cFileName);
                fileList.push_back(fileName);
            }
        }
        while (FindNextFile(hFind, &ffd) != 0);
    }
    if (GetLastError() != ERROR_NO_MORE_FILES)
        fileList.clear();
    FindClose(hFind);
    return fileList;
}
